﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Data.Objects.DataClasses;

using System.EntityFramework.Extensions.Parser.Interpreter.Tokens;
using System.EntityFramework.Extensions.Metadata;


namespace System.EntityFramework.Extensions.Parser.Interpreter.MethodCallInterpreters
{
    /// <summary>
    /// Interpreter of method call with boolean result ( participating in binary expressions )
    /// </summary>
    sealed class EntityMemberTerminalMethodCallExpressionInterpreter
        :IInterpreter,IInterpreterChaining
    {
        #region IInterpreterChainging Members

        IInterpreter mNextInterpreter = null;
        /// <summary>
        /// <see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreterChaining"/>
        /// </summary>
        public IInterpreter NextInterpreter
        {
            get
            {
                return mNextInterpreter;
            }
            set
            {
                mNextInterpreter = value;
            }
        }

        #endregion

        #region IInterpreter Members
        /// <summary>
        /// <see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/>
        /// </summary>
        /// <typeparam name="T"><see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/></typeparam>
        /// <param name="expression"><see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/></param>
        /// <returns><see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/></returns>
        public string InterpreteExpression<T>(System.Linq.Expressions.Expression expression)
            where T : EntityObject, new()
        {
            if (IsValidInterpreter(expression))
            {
                string columnName = string.Empty;
                string formated = string.Empty;
                

                MethodCallExpression methodCallExpression = expression as MethodCallExpression;
                MemberExpression memberExpression = methodCallExpression.Object as MemberExpression;
                columnName = MetadataAccessor.GetColumnNameByEdmProperty<T>(memberExpression.Member.Name);

                string resultArgument = InterpreterFactory.GetInterpreter(methodCallExpression.Arguments[0].GetType())
                                        .InterpreteExpression<T>(methodCallExpression.Arguments[0]);

                switch (methodCallExpression.Method.Name)
                {
                    case "Contains":
                        {
                            formated = InterpreterFactory.GetTokenFactory().PrepareElement(string.Format("%{0}%", resultArgument), typeof(String));
                        } break;
                    default: break;
                }

                return string.Format("{0} LIKE {1}",columnName, formated);
                
            }
            else
            {
                if (NextInterpreter != null)
                    return NextInterpreter.InterpreteExpression<T>(expression);
                else
                    throw new InvalidOperationException("Invalid Interpreter");
            }
        }
        /// <summary>
        /// <see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/>
        /// </summary>
        /// <param name="expression"><see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/></param>
        /// <returns><see cref="System.EntityFramework.Extensions.Parser.Interpreter.IInterpreter"/></returns>
        public bool IsValidInterpreter(System.Linq.Expressions.Expression expression)
        {
            //If is terminal expression over a entity object member
            if ((expression is MethodCallExpression))
            {
                MethodCallExpression methodCallExpression = expression as MethodCallExpression;
                if (methodCallExpression.Method.ReturnType == typeof(Boolean) && methodCallExpression.Object is MemberExpression)
                {
                    MemberExpression memberExpression = methodCallExpression.Object as MemberExpression;
                    if (typeof(EntityObject).IsAssignableFrom(memberExpression.Expression.Type))
                        return true;
                    else
                        return false;
                }
                else
                    return false;
            }
            else
                return false;
        }

        #endregion
    }
}
